<?php
namespace App\Services\Oauth;

use App\Models\MysqlDb\CompanyModel;
use App\Models\MysqlDb\PaymentOrderModel;
use App\Models\StatusCode;
use App\Services\BaseService;
use App\Services\CommonReturn;
use App\Services\CommonServices;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use tinymeng\OAuth2\Helper\ConstCode;
use tinymeng\OAuth2\Helper\Str;
use tinymeng\OAuth2\OAuth;
use tinymeng\tools\StringTool;
use tinymeng\tools\Tool;

/**
 * Class PayService
 * @package app\common\service
 * @Author: TinyMeng <666@majiameng.com>
 * @Created: 2020/8/14
 */
class OauthService extends BaseService {
    /**
     * @var
     */
    public $config;
    /**
     * @var
     */
    public $company;
    /**
     * @var
     */
    public $params;

    /**
     * @var
     */
    public $type;
    /**
     * @var
     */
    public $app_id;

    /**
     * 构造函数
     */
    public function __construct()
    {
        $this->model = new PaymentOrderModel();
    }


    /**
     * @return void
     */
    public function index(){
        /** 获取第三方登录配置 */
        $this->getConfig();
        if(!empty($this->params['code']) || !empty($this->params['auth_code'])){
            $result = $this->callback();
            return $result;
        }else{
            $redirectUrl = $this->login();
            header("HTTP/1.1 301 Moved Permanently");
            header("Location: ".$redirectUrl);
            exit();
        }
    }


    /**
     * Description:  获取第三方登录配置
     * @author: JiaMeng <666@majiameng.com>
     * Updater:
     */
    public function getConfig(){
        $name = $this->params['name'];
        $type = $this->params['type'];
        $config = config('oauth');

        if(empty($type)){
            $data = (new OauthConfigService())->getParamsConfig($this->company,'oauth_'.$name);
            $this->config = array_merge($config[$name],$data);
        }else{
            $data = (new OauthConfigService())->getParamsConfig($this->company,'oauth_'.$name.'_'.$type);
            $this->config = array_merge($config[$name][$type],$data);
        }
    }

    /**
     * Description:  第三方登陆
     * @param $name
     * @return mixed
     * @author: JiaMeng <666@majiameng.com>
     * Updater:
     */
    public function login(){
        $name = $this->params['name'];
        /** 获取配置 */
        $oauth = OAuth::$name($this->config)->mustCheckState();
        if(Tool::isMobile() || Tool::isWeiXin()){
            $oauth->setDisplay('mobile');
        }
        return $oauth->getRedirectUrl();
    }


    /**
     * Description:  第三方登录回调
     * @author: JiaMeng <666@majiameng.com>
     * Updater:
     * @param $name
     */
    public function callback(){
        $name = $this->params['name'];
        try {
            $oauth = OAuth::$name($this->config);

            /** 获取第三方用户信息 */
            $userInfo = $oauth->userInfo();
            $userInfo['app_id'] = $this->config['app_id'];
            Log::channel('info')->info(json_encode($userInfo));

            /** 获取用户信息 */
            $user = $this->getOauthUser($userInfo);

            //获取返回的用户信息
            $user = User::where(['user_id' => $user->user_id])->first();

            if($userInfo['type'] == \tinymeng\OAuth2\Helper\ConstCode::TYPE_WECHAT_APPLETS){//微信小程序登录
                $result = $this->wechatAppletsLogin($user,$userInfo);
            }else{
                if(!empty($_GET['referer'])){
                    $referer = base64_decode($_GET['referer']);
                    //跳转来源页
                    $data = [
                        "user_id"=>$user->user_id,
                        "openid"=>$userInfo['open_id']??'',
                    ];
                    $referer = $referer.(strstr($referer,'?')?"&":"?").http_build_query($data);
                    header("HTTP/1.1 301 Moved Permanently");
                    header("Location: ".$referer);
                    exit();
                }else{
                    //跳转首页
                    var_dump($user);die;
                }
            }

            return $result;
        }catch (\Exception $e) {
            CommonReturn::fail(StatusCode::COMMON_UNKNOWN, $e->getFile().$e->getLine().$e->getMessage());
        }
    }

    /**
     * 微信小程序登录
     * @param $user
     * @param $userInfo
     * @return array
     */
    public function wechatAppletsLogin($user,$userInfo){
        /** 用户操作日志 */
        $logParams = [
            'user_id'=>$user['user_id'],
            'company_id'=>$user['company_id'],
            'truename'=>$user['truename'],
            'user_ip'=>CommonServices::ip(),
        ];
        event(new UserOptionLogEvent(UserOptionLog::TYPE_LOGIN,$logParams));

        //格式化用户信息
        $result = (new LoginServices())->getLoginUserInfo($this->config['user_type'],$user);
        $result['open_id'] = $userInfo['open_id'];
        return $result;
    }

    /**
     * 密码登录
     * @param $user
     * @return array
     */
    public function otherLogin($user){
        /** 用户操作日志 */
        $logParams = [
            'user_id'=>$user['user_id'],
            'company_id'=>$user['company_id'],
            'truename'=>$user['truename'],
            'user_ip'=>CommonServices::ip(),
        ];
        event(new UserOptionLogEvent(UserOptionLog::TYPE_LOGIN,$logParams));

        $result = (new LoginServices())->getLoginUserInfo(\App\Models\ConstCode::TYPE_ADMINISTRATORS,$user);
        return $result;
    }

    /**
     * 获取小程序公告
     * @return array
     */
    public function getNotice($user_type,$company_id){
        $result = Notice::getNoticeByUserType($user_type,$company_id);
        if(!empty($result)){
            $result = $result->toArray();
        }
        return $result;
    }


    /**
     * Description:  获取用户信息
     * @author: JiaMeng <666@majiameng.com>
     * Updater:
     * @param $params
     *  |-- int type    登录类型(必传)
     *  |-- int union_id    用户唯一id
     *  |-- string avatar   头像
     *  |-- int open_id     用户open_id(必传)
     *  |-- time birthday   用户生日
     *  |-- string username 用户名
     *  |-- string nickname 昵称
     *  |-- int gender      性别
     * @return object
     */
    public function getOauthUser($params){
        Db::beginTransaction();
        try {
            /**
             * 1. 获取第三方绑定信息
             * @var  object $userBang
             */
            $oauthData = [
                'user_id' => 0,
                'open_id' => $params['open_id'] ?? Str::random(32),
                'union_id' => $params['union_id'] ?? Str::random(32),
                'app_id' => $params['app_id'] ?? '',
                'channel' => $params['channel'] ?? '',
                'session_key' => $params['session_key']??'',
                'type' => $params['type']??'',
                'status' => ConstCode::STATUS_NORMAL,
            ];
            $userBang = $this->getOauth($oauthData);
            /**
             * 2. 判断user_id是否为0 如果为0 新增用户记录修改绑定表用户id
             */
            if ($userBang->user_id == 0) {
                /**
                 * 3. 创建用户主表信息数据
                 * @var object $user
                 */
                $userData = [
                    'nickname' => empty($params['nickname']) ? '微信用户'.StringTool::generateRandomString(5) : $params['nickname'],
                    'avatar' => empty($params['avatar']) ? config('params.default_avatar') : $params['avatar'],
                    'email' => empty($params['email']) ? '' : $params['email'],
                    'sign' => empty($params['sign']) ? '' : $params['sign'],
                    'gender' => empty($params['gender']) ? 0 : $params['gender'],
                    'birthday' => empty($params['birthday']) ? date('Y-m-d') : $params['birthday'],
                    'status' => ConstCode::STATUS_NORMAL,//离线状态
                    'access_token' => Str::random(32),
                    'update_time' => NOW_TIME,
                    'create_time' => NOW_TIME,
                ];
                $user = User::create($userData);
                /** @var int user_id 修改绑定表user_id */
                $userBang->user_id = $user->user_id;
                /** 修改绑定表用户id */
                $userBang->save();
            } else {
                /**
                 * 查询用户主表信息数据
                 * @var  $user
                 */
                $user = User::where(['user_id' => $userBang->user_id])->first();
            }

            DB::commit();//  提交事务
            return $user;
        } catch (\Exception $e) {
            Db::rollback();// 回滚事务
            CommonReturn::fail(StatusCode::COMMON_UNKNOWN, $e->getMessage());
        }
    }

    /**
     * Description:  获取第三方绑定信息
     * @author: JiaMeng <666@majiameng.com>
     * Updater:
     * @param $data
     * @return mixed
     */
    public function getOauth($data){
        /**
         * 查询用户唯一标识
         * 1.微信PC登录 && 微信公众号登录 && 微信App登录 && 微信小程序登录
         *      同时绑定到一个微信开放平台会获取用户唯一标识以用于同步用户.
         * 2.QQPC登录 && QQApp登录
         *      QQ互联UnionID应用打通申请后会获取用户唯一标识以用于同步用户.
         */
        if(!empty($data['union_id'])){
            $where = ['union_id'=>$data['union_id'],'status'=>ConstCode::STATUS_NORMAL];
            $unOauth = UserOauth::where($where)->first();
            if(!empty($unOauth)){
                /** 2024-06-17 update 不再使用uuid进行账号绑定 */
                $data['user_id'] = $unOauth->user_id;
            }
        }

        if(in_array($data['channel'],[ConstCode::TYPE_QQ,ConstCode::TYPE_WECHAT])){
            //qq 微信 账户union_id是唯一身份识别,但是open_id是渠道识别(例:手机web,手机App,pc web,小程序)
            /** 查询用户登录第三方绑定 */
            $where = [
                'open_id'=>$data['open_id'],
                'status'=>ConstCode::STATUS_NORMAL
            ];
            $oauth = UserOauth::where($where)->first();
            if(empty($oauth)){
                $oauth = UserOauth::create($data);
            }else{
                if(isset($data['session_key'])){
                    $oauth->session_key = $data['session_key'];
                    $oauth->save();
                }
            }

            if(!empty($data['app_id']) && (empty($oauth->app_id) || $oauth->app_id != $data['app_id'])) {
                $oauth->app_id = $data['app_id'];
                $oauth->save();
            }

            /** 修改用户union_id,修复以前没有存储union_id的逻辑问题 */
            if(!empty($data['union_id']) && (empty($oauth->union_id) || $oauth->union_id != $data['union_id'])){
                $oauth->union_id = $data['union_id'];
                $oauth->save();

                /** 2024-06-17 update 不再使用uuid进行账号绑定 */
                //获取uuid绑定的所有oauth
                $where = ['union_id'=>$data['union_id'],'status'=>ConstCode::STATUS_NORMAL];
                $unOauth = UserOauth::where($where)->get();
                $applet_user_id = 0;
                if(count($unOauth) >= 2){
                    //获取uuid绑定的所有oauth
                    foreach ($unOauth as $value){
                        if($value['type'] == ConstCode::TYPE_WECHAT_APPLETS){
                            $applet_user_id = $value['user_id'];//查找小程序使用的用户id
                            break;
                        }
                    }
                    if(!empty($applet_user_id)){
                        //对比其他绑定，user_id使用小程序user_id
                        foreach ($unOauth as $value){
                            if($value['type'] != ConstCode::TYPE_WECHAT_APPLETS && $value['user_id']!=$applet_user_id){
                                $value->old_user_id = $value->user_id;
                                $value->user_id = $applet_user_id;
                                $value->save();
                            }
                        }
                    }
                }
            }
            return $oauth;
        }else{
            //sina github alipay 账户union_id已经是唯一身份识别了
            if(empty($unOauth)){
                //创建oauth
                $unOauth = UserOauth::create($data);
            }else{
                if(isset($data['session_key'])){
                    $unOauth->session_key = $data['session_key'];
                    $unOauth->save();
                }
                //更新open_id,部分open_id是用户的access_token,会发生变化
                if($unOauth->open_id != $data['open_id']){
                    $unOauth->open_id = $data['open_id'];
                    $unOauth->save();
                }
            }
            return $unOauth;
        }
    }

    /**
     * @return void
     */
    public function getCompany()
    {
        //获取公司信息
        $this->company = CompanyModel::getByAppid($this->app_id);
    }
}
